<template>
  <section class="largeUpFile">
    <div class="btn-box">
      <el-button @click="openFile($event)">
        <i class="el-icon-upload"></i>
        <span>选择文件</span>
      </el-button>&nbsp;
      <input type="file" style=" display: none;" @change="changeFile($event)">
      <el-button type="primary" :loading="btnLoading" @click="beginLoad()">开始上传</el-button>
    </div>
    <ul class="file-list">
      <li v-for="(item,index) in fileList" :key="index" @click="onClickItem(item)">
        <span>{{item.file?item.file.name:item.fileName}}</span>
        <span v-if="item.status=='before'" class="error-color">待上传</span>
        <span v-else-if="item.status=='after'" class="success-color">已完成</span>
        <span v-else-if="item.status=='plan'" class="warning-color">准备上传</span>
        <span v-else>
          <span class="success-color">正在上传：{{item.progress}}%</span>
          &nbsp; &nbsp;
          <span v-if="item.status=='stop'" class="success-color" @click.stop="continueLoad(item)">继续</span>
          <span v-else class="error-color" @click.stop="stopLoad(item)">暂停</span>
        </span>
        <i class="el-icon-delete error-color" title="删除" @click.stop="onDel(item,index)"></i>
      </li>
    </ul>
    <el-select v-model="urlArray" multiple @change="changeInput" v-show="false">
      <el-option v-for="(item,index) in fileList" :key="index" :label="item.fileName" :value="item.fileName"></el-option>
    </el-select>
  </section>
</template>
<script>
let OSS = require("ali-oss");
import Config from "@/_config/config.js";
// 回调事件：cleckItem
export default {
  props: {
    value: {
      type: Array,
      default: function() {
        return [];
      }
    },
    //限制类型 (image/png,image/jpeg)
    limitType: {
      type: Array,
      default: function() {
        return [];
      }
    },
    limit: {
      //上传个数
      type: Number,
      default: 5
    },
    //文件大小0：不限制
    fileSize: {
      type: Number,
      default: 0
    },
    //文件名字默认会加上日期
    fileName: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      urlArray: [], //当前上传成功的地址集合
      fileList: [], //上传列表
      filePath: "FILE_UPLOAD/", //上传路径
      maxLoadCount: 2, //最大上传数
      curLoadCount: 0,
      btnLoading: false
    };
  },
  created() {
    let th = this;
    let date = new Date();
    let m = date.getFullYear() + "-" + date.getMonth() + 1;
    th.filePath += m + "/";
    th.urlArray = th.value;
    th.setInitData(th.value);
  },
  methods: {
    setInitData(arr) {
      let th = this;
      if (arr.length == 0) {
        th.fileList = [];
      } else {
        if (th.fileList.length > 0) return;
        arr.forEach(el => {
          th.fileList.push({
            progress: 100,
            file: null,
            status: "after",
            fileName: el
          });
        });
      }
    },
    changeInput() {
      this.$emit("change", this.urlArray);
    },
    //删除
    onDel(obj, index) {
      let th = this;
      let delModel = function() {
        //判断如果删除的项是否已经在队列里就启动下一个
        if (
          obj.status == "loading" ||
          obj.status == "stop" ||
          obj.status == "plan"
        ) {
          th.curLoadCount--;
          //启动上传
          th.beginLoad("plan");
        }
        th.fileList.splice(index, 1);
        th.getSuccessFile();
      };
      if (obj.status == "loading" || obj.status == "stop") {
        th.$confirm(`文件正在上传，确定删除?`, "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
          center: true
        })
          .then(() => {
            //这里要判断是因为，可能用户在弹窗很久不点击 确定
            if (obj.status == "loading" || obj.status == "stop") {
              obj.OSS.cancel();
            }
            delModel();
          })
          .catch(() => {});
      } else {
        delModel();
      }
    },
    //继续上传
    continueLoad(obj) {
      let th = this;
      obj.status = "loading";
      th.$api.getTemporaryAKAndToken("web").then(res => {
        th.initOSS(res, obj);
      });
    },
    //暂停上传
    stopLoad(obj) {
      obj.status = "stop";
      obj.OSS.cancel();
    },
    //上传接口
    async httpQequest(obj, th) {
      // object表示上传到OSS的名字，可自己定义
      // file浏览器中需要上传的文件，支持HTML5 file 和 Blob类型
      let j = {
        partSize: 200 * 1024,
        parallel: 1,
        progress: async function(percentage, checkpoint) {
          // 记录断点, 如果关闭了浏览器，然后重新启动继续上传的话，是不行的，请参考上边对file对象的描述
          obj["checkpoint"] = checkpoint;
          obj.progress = (percentage * 100).toFixed(1);
          if (percentage == 1) {
            th.curLoadCount--;
            obj.status = "after";
            th.getSuccessFile();
            //启动上传
            th.beginLoad("plan");
          }
          // console.log(percentage, checkpoint);
        }
      };
      //是否继续上传
      if (obj.checkpoint) j["checkpoint"] = obj.checkpoint;
      try {
        obj.status = "loading";
        let result = await obj.OSS.multipartUpload(obj.fileName, obj.file, j);
      } catch (error) {
        console.log(error);
      }
    },
    //开始上传
    beginLoad(type) {
      let th = this;
      if (th.fileList.length == 0) {
        return;
      }
      let arr = [];
      //判断是否直接上传
      if (type == "plan") {
        for (let i = 0; i < th.fileList.length; i++) {
          let d = th.fileList[i];
          if (d.status != "plan") continue;
          arr.push(d);
        }
      } else {
        //过滤已经上传了的文件
        for (let i = 0; i < th.fileList.length; i++) {
          let d = th.fileList[i];
          if (d.status != "before") continue;
          d.status = "plan"; //设置准备状态
          arr.push(d);
        }
      }
      if (arr.length == 0) return;
      th.btnLoading = true;
      //获取临时权限
      th.$api.getTemporaryAKAndToken("web").then(res => {
        th.btnLoading = false;
        if (!res.excute) {
          return;
        }
        arr.forEach(el => {
          th.initOSS(res, el);
        });
      });
    },
    //初始化上传
    initOSS(config, obj) {
      let th = this;
      //判断是否超过最大上传数
      if (th.curLoadCount >= th.maxLoadCount) {
        return;
      }
      //追加最大上传数
      th.curLoadCount++;
      obj["OSS"] = new OSS({
        //   region: "oss-cn-hangzhou",
        accessKeyId: config.accessKeyId,
        accessKeySecret: config.accessKeySecret,
        stsToken: config.securityToken,
        endpoint: "https://oss-cn-beijing.aliyuncs.com",
        bucket: config.bucket
      });
      (function(_obj, _th) {
        _th.httpQequest(_obj, _th);
      })(obj, th);
    },
    //选择文件
    changeFile(e) {
      let th = this;
      if (e.target.files.length == 0) return;
      let file = e.target.files[0];

      //判断文件类型
      if (th.limitType.length > 0) {
        let index = th.limitType.findIndex(d => {
          return d == file.type;
        });
        if (index == -1) {
          th.$message.warning("文件类型有误！");
          return;
        }
      }
      if (th.fileSize && file.size > th.fileSize) {
        th.$message.warning(`最大支持${Math.round(th.fileSize / 1048576)}m`);
        return;
      }
      if (th.fileList.length >= th.limit) {
        th.$message.warning("数量超过限制！");
        return;
      }
      let fnArr = file.name.split(".");
      let fName = `${th.filePath}${th.fileName}${new Date().getTime()}.${
        fnArr[fnArr.length - 1]
      }`;
      th.fileList.push({
        progress: 0,
        file: file,
        status: "before",
        fileName: fName
      });
    },
    openFile(e) {
      let th = this;
      let el = e.target.offsetParent;
      let elFile = el.querySelector("[type='file']");
      elFile.click();
    },
    //获取上传成功的文件路径
    getSuccessFile() {
      let th = this;
      let arr = [];
      th.fileList.forEach(el => {
        if (el.status == "after") {
          arr.push(el.fileName);
        }
      });
      th.urlArray = arr;
      th.$emit("input", arr);
    },
    //点击上传的项目
    onClickItem(obj) {
      const th = this;
      if (obj.file) th.$emit("cleckItem", obj.file);
      else th.$emit("cleckItem", obj.fileName);
    }
  },
  watch: {
    value(n) {
      console.log(n);
      this.setInitData(n);
    }
  }
};
</script>
<style lang="scss">
.largeUpFile {
  .btn-box {
    position: relative;
  }
  .file-list {
    margin-top: 5px;
    padding: 0;
    > li {
      list-style: none;
      font-size: 16px;
      margin-bottom: 5px;
      &:hover {
        background-color: rgb(245, 245, 245);
        cursor: pointer;
      }
      > span {
        margin-right: 20px;
      }
    }
  }
}
</style>

